using System;
using System.Collections;

namespace Minesweeper02
{
	/// <summary>
	/// Summary description for MathBase.
	/// </summary>
	public struct StatusMine{
		//if item have mine
		public bool IsMine;
		//near mine of item
		public int NearMine;
		//the remain near mine of a item when game start
		public int NearMineRemain;
		//property of item
		/// <summary>
		/// 0:nolabel
		/// 1:LeftClick,if not have mine it display nearmine,or  
		/// -1:if check mark Mark(?) display ? when leftclick on nolabelitem
		/// -2:the flag mine display
		/// </summary>
		public int Status;
	}
	public struct DrawQueue
	{
		// X
		public int X;
		// Y
		public int Y;
		/// <summary>
		//the index of property image
		/// 0:nomine0
		/// 1:nomine1
		/// 2:nomine2
		/// 3:nomine3
		/// 4:nomine4
		/// 5:nomine5
		/// 6:nomine6
		/// 7:nomine7
		/// 8:nomine8
		/// 9:nolabel
		/// 10:minelabeled
		/// 11:undefinemine
		/// 12:mineclicked
		/// 13:nominecheckmine
		/// 14:mineuncheck
		/// </summary>
		public int NImg;
		public void  Init(int _X,int _Y,int _NImg){
            this.X=_X;
			this.Y=_Y;
			this.NImg=_NImg;
        }
    } 
	public class MathBase
	{
		private int rows;
		private int columns;
		private int totalMine;
		private int totalArea;
		private int remainArea;
		private int remainMine;
		//array contain the naer item of a item
		private int[,] Near=new int[8,2]{{-1,-1},{-1,0},{-1,1},{0,1},{1,1},{1,0},{1,-1},{0,-1}};
		//when start new property is plused one to make new random mine
		private int numberPlayed;
		//check the game is missed
		private bool isFinished;
		//check the game is win
		private bool isWin;
		//property is display mark or not
		private bool mark;
		//the queue to process image
		private DrawQueue dq;
		//array contain the property of items
		private StatusMine[,] arrayMine;
		private Queue thisQueue;
		public bool Mark
		{
			set{
				mark=value;
			}
			get{
				return mark;
			}
		}
		public bool IsFinished
		{
			set{
				isFinished=value;
			}
			get{
				return isFinished;
			}
		}
		public bool IsWin{
			get{
				return isWin;
			}
		}
		public Queue ThisQueue{
			set{
				thisQueue=value;
			}
			get{
				return thisQueue;
			}
		}
		public int RemainMine{
			get{
				return remainMine;
			}
		}
		//the method to init new property of game
		public void InitAttribute(int _columns,int _rows,int _totalMine){
			columns=_columns;
			rows=_rows;
			totalMine=_totalMine;
			totalArea=columns*rows;
			arrayMine=new StatusMine[columns,rows];
		}
		//the method is used when start new game
		public void RestartAttributeGame(){
			remainArea=totalArea;
			remainMine=totalMine;
			isFinished=false;
			isWin=false;
			numberPlayed++;
			for (int x=0;x<columns;x++)
				for (int y=0;y<rows;y++){
					this.arrayMine[x,y].IsMine=false;
					this.arrayMine[x,y].NearMine=0;
					this.arrayMine[x,y].NearMineRemain=0;
					this.arrayMine[x,y].Status=0;
			}
		}
		
		public MathBase(int _columns,int _rows,int _totalMine)
		{
			//
			// TODO: Add constructor logic here
			//
			thisQueue=new Queue();
			numberPlayed=0;
			dq=new DrawQueue();
			InitAttribute(_columns,_rows,_totalMine);
			RestartAttributeGame();
		}
		#region MethodComponent
		public void LeftDown(int x,int y){
            if (this.arrayMine[x,y].Status==0 || this.arrayMine[x,y].Status==-1)
			dq.Init(x,y,0);
			thisQueue.Enqueue(dq);
        }

		public void BothDown(int x,int y){
			LeftDown(x,y);
			for (int i=0;i<8;i++)
			{
				if ((x+Near[i,0]>=0)&&(x+Near[i,0]<columns)&&(y+Near[i,1]>=0)&&(y+Near[i,1]<rows))
				{
						LeftDown(x+Near[i,0],y+Near[i,1]);
				}
			}
		}
		public void RightClick(int x,int y){
			switch(this.arrayMine[x,y].Status){
				case 0:
					this.arrayMine[x,y].Status=-2;
					dq.Init(x,y,10);
					thisQueue.Enqueue(dq);
					for (int i=0;i<8;i++)
					{
						if ((x+Near[i,0]>=0)&&(x+Near[i,0]<columns)&&(y+Near[i,1]>=0)&&(y+Near[i,1]<rows))
						{
							this.arrayMine[x+Near[i,0],y+Near[i,1]].NearMineRemain--;
						}
					}
					this.remainMine--;
					this.remainArea--;
					break;
                case -1:
					this.arrayMine[x,y].Status=0;
					dq.Init(x,y,9);
					thisQueue.Enqueue(dq);
					break;
				case -2:
					if(mark)
					{
						this.arrayMine[x,y].Status=-1;
						dq.Init(x,y,11);
						thisQueue.Enqueue(dq);
					}
					else
					{
						this.arrayMine[x,y].Status=0;
						dq.Init(x,y,9);
						thisQueue.Enqueue(dq);
					}
					for (int i=0;i<8;i++)
					{
						if ((x+Near[i,0]>=0)&&(x+Near[i,0]<columns)&&(y+Near[i,1]>=0)&&(y+Near[i,1]<rows))
						{
							this.arrayMine[x+Near[i,0],y+Near[i,1]].NearMineRemain++;
						}
					}
					this.remainMine++;
					this.remainArea++;
					break;
				default:
					//noaction
					break;
			}
		}
		public void LeftClick(int x,int y){
			if (this.arrayMine[x,y].Status==0 || this.arrayMine[x,y].Status==-1){
				this.arrayMine[x,y].Status=1;
				if (this.arrayMine[x,y].IsMine)
				{
					isFinished=true;   
					dq.Init(x,y,12);
					thisQueue.Enqueue(dq);
				}
				else{
					dq.Init(x,y,arrayMine[x,y].NearMine);
					thisQueue.Enqueue(dq);
					this.remainArea--;
					if (this.remainArea==this.remainMine){
						isWin=true;
					}
					if (arrayMine[x,y].NearMine==0)
					{
						for (int i=0;i<8;i++)
						{
							if ((x+Near[i,0]>=0)&&(x+Near[i,0]<columns)&&(y+Near[i,1]>=0)&&(y+Near[i,1]<rows))
							{
								if(this.arrayMine[x+Near[i,0],y+Near[i,1]].Status==0 || this.arrayMine[x+Near[i,0],y+Near[i,1]].Status==-1)
								{
									LeftClick(x+Near[i,0],y+Near[i,1]);
								}
							}
						}
					}
				} 
			}
		}
		public void BothClick(int x,int y){
			if (this.arrayMine[x,y].NearMineRemain==0 && this.arrayMine[x,y].Status==1)
			{
				for (int i=0;i<8;i++)
				{
					if ((x+Near[i,0]>=0)&&(x+Near[i,0]<columns)&&(y+Near[i,1]>=0)&&(y+Near[i,1]<rows))
					{
						if(this.arrayMine[x+Near[i,0],y+Near[i,1]].Status==0 || this.arrayMine[x+Near[i,0],y+Near[i,1]].Status==-1)
						{
							LeftClick(x+Near[i,0],y+Near[i,1]);
						}
					}
				}
			}
			else{
				this.BothOut(x,y);
			}

		}
		public void LeftMove(int x,int y){
			if (x>=0 && x<columns && y>=0 && y<rows)
			{
				this.LeftDown(x,y);
			}
		}
		public void BothMove(int x,int y){
			this.BothDown(x,y);
		}
		public void LeftOut(int x,int y){
			if ((this.arrayMine[x,y].Status==0 || this.arrayMine[x,y].Status==-1) && x>=0 && x<columns && y>=0 && y<rows)
			{
				dq.Init(x,y,9);
				thisQueue.Enqueue(dq);
			}
			else{//
			}
		}
		public void BothOut(int x,int y){
			LeftOut(x,y);
			for (int i=0;i<8;i++)
			{
				if ((x+Near[i,0]>=0)&&(x+Near[i,0]<columns)&&(y+Near[i,1]>=0)&&(y+Near[i,1]<rows))
				{
				    LeftOut(x+Near[i,0],y+Near[i,1]);
				}
			}

		}
		//the method use when player miss the game
		public void Finished(){
			for(int x=0;x<columns;x++)
				for (int y=0;y<rows;y++){
					switch(this.arrayMine[x,y].Status){
						case 0:
							if (this.arrayMine[x,y].IsMine){
								dq.Init(x,y,14);
								thisQueue.Enqueue(dq);
							}
							break;
						case -1:
							if(this.arrayMine[x,y].IsMine){
								dq.Init(x,y,14);
								thisQueue.Enqueue(dq);
							}
							break;
						case -2:
							if (!this.arrayMine[x,y].IsMine){
								dq.Init(x,y,13);
								thisQueue.Enqueue(dq);
							}
							break;
						default:
							break;
					}
				}

		}
		//the method appear when player win the game
		public void Win(){
			this.remainMine=0;
			for(int x=0;x<columns;x++)
				for(int y=0;y<rows;y++){
					if (arrayMine[x,y].Status==0 || arrayMine[x,y].Status==-1){
						this.arrayMine[x,y].Status=-2;
						dq.Init(x,y,10);
						thisQueue.Enqueue(dq);
					}
				}
		}
		//make the array of mine property 
		public void MakeMineMap(int _click)
		{
			MakeRandMine(_click);
			for (int i=0;i<columns;i++)
				for (int j=0;j<rows;j++){
					this.arrayMine[i,j].NearMine=countMine(i,j);
					this.arrayMine[i,j].NearMineRemain=this.arrayMine[i,j].NearMine;
				}
        }
		//count the near mine
		public int countMine(int x,int y)
		{
			int c=0;
			for (int i=0;i<8;i++)
			{
				if ((x+Near[i,0]>=0)&&(x+Near[i,0]<columns)&&(y+Near[i,1]>=0)&&(y+Near[i,1]<rows)&&(this.arrayMine[x+Near[i,0],y+Near[i,1]].IsMine))
				{
					c++;
				}
			}
			return c;
		}

		//make rand mine
		public void MakeRandMine(int _click)
		{
			int count,i,currentno;
			count=0;
			Random randobj=new Random(numberPlayed);
			currentno=_click;
			while (count<totalMine){
                i=randobj.Next(0,totalArea-1);
				currentno=currentno+i;
				currentno=currentno%totalArea;
				if (currentno!=_click && !this.arrayMine[currentno%columns,(int)(Math.Floor(currentno/columns))].IsMine){
					this.arrayMine[currentno%columns,(int)(Math.Floor(currentno/columns))].IsMine=true;
					count++;
				}
			}			
		}
		#endregion
	}
}
		
